﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
using SnippetBox.businesslogic;
using System.Linq;
using System.Windows.Threading;
using System.IO;

namespace SnippetBox
{
  public partial class MainWindow : Window
  {
    private Snippet selectedsnippet;
    private Topic selectedtopic;
    private List<Snippet> snippets;
    private List<Topic> topics;
    private DispatcherTimer autosavetimer;

    public MainWindow()
    {
      InitializeComponent();

      if (File.Exists(@"C:\SnippetBox_Topics.xml"))
      {
        topics = XMLSerializer.DeserializeFromXML(topics);
        foreach (var topic in topics)
        {
          tv_topic.Items.Add(topic);
        }

        if (File.Exists(@"C:\SnippetBox_Snippets.xml"))
        {
          snippets = XMLSerializer.DeserializeFromXML(snippets);
          lv_snippets.ItemsSource = snippets;
        }
      }
      else
      {
        snippets = new List<Snippet>();
        topics = new List<Topic>();
      }

      selectedsnippet = new Snippet();
      selectedtopic = new Topic();
      autosavetimer = new DispatcherTimer();
      autosavetimer.Interval = TimeSpan.FromMinutes(2);
      autosavetimer.Tick += delegate(object sender, EventArgs e)
      {
        SaveSnippet();
        lbl_messages.Text = "Autosaved at " + DateTime.Now.ToString();
        autosavetimer.Stop();
      };

      avalonedit.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
      avalonedit.ShowLineNumbers = true;
    }

    private void TopicSelector(Topic topic)
    {
      TreeViewItem treeviewitem = tv_topic.ItemContainerGenerator.ContainerFromItem(topic) as TreeViewItem;
      treeviewitem.IsSelected = true;
    }

    private void SnippetSelector(Snippet snippet)
    {
      ListViewItem listviewitem = lv_snippets.ItemContainerGenerator.ContainerFromItem(snippet) as ListViewItem;
      listviewitem.IsSelected = true;
    }

    private void SaveSnippet()
    {
      selectedsnippet.Code = avalonedit.Text;
      btn_savesnippet.Visibility = Visibility.Collapsed;
      XMLSerializer.SerializeToXML(snippets);
    }

    private void ResetNewSnippet()
    {
      tb_newsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_newsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_newsnippet_name.Text = "";
      tb_newsnippet_description.Text = "";
    }

    private void ResetEditSnippet()
    {
      tb_editsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_editsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_editsnippet_name.Text = "";
      tb_editsnippet_description.Text = "";
    }

    private void ResetNewTopic()
    {
      tb_newtopic.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_newtopic.Text = "";
    }

    private void ResetEditTopic()
    {
      tb_edittopic.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_edittopic.Text = "";
      lbl_edittopic_error.Content = "";
    }

    private void RebuildTreeview()
    {
      tv_topic.Items.Clear();

      foreach (var topic in topics)
      {
        tv_topic.Items.Add(topic);
      }
    }

    private void AddNewTopic()
    {
      if (tb_newtopic.Text != "")
      {
        List<Topic> topiccount = topics.Where(topic => topic.Name == tb_newtopic.Text).ToList();

        if (topiccount.Count == 0)
        {
          Topic topic = new Topic()
          {
            Name = tb_newtopic.Text
          };

          tv_topic.Items.Add(topic);
          topics.Add(topic);

          XMLSerializer.SerializeToXML(topics);

          ResetNewTopic();
          pop_newtopic.IsOpen = false;

          TopicSelector(topic);
        }
        else
        {
          lbl_newtopic_error.Content = "Topic already exists!";
        }
      }
      else
      {
        tb_newtopic.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }
    }

    private void AddNewSnippet()
    {
      if (tb_newsnippet_name.Text != "" && tb_newsnippet_description.Text != "")
      {
        Snippet snippet = new Snippet()
        {
          Name = tb_newsnippet_name.Text,
          Date = DateTime.Now.ToString(),
          Description = tb_newsnippet_description.Text,
          Topic = selectedtopic,
          Code = "Add Code here!"
        };

        snippets.Add(snippet);
        lv_snippets.ItemsSource = snippets.Where(snip => snip.Topic.Name == selectedtopic.Name).ToList();

        XMLSerializer.SerializeToXML(snippets);

        ResetNewSnippet();
        pop_newsnippet.IsOpen = false;

        lv_snippets.SelectedIndex = snippets.Where(snip => snip.Topic.Name == selectedtopic.Name).ToList().Count - 1;
      }
      else if (tb_newsnippet_name.Text == "")
      {
        tb_newsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }
      else if (tb_newsnippet_description.Text == "")
      {
        tb_newsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }
      else
      {
        tb_newsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
        tb_newsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }
    }

    private void EditTopic()
    {
      if (tb_edittopic.Text != "")
      {
        Topic edittopic = tv_topic.SelectedItem as Topic;
        Topic newtopic = new Topic()
        {
          Name = tb_edittopic.Text
        };

        if (!topics.Contains(newtopic))
        {
          edittopic.Name = tb_edittopic.Text;

          List<Snippet> editsnippets = snippets.Where(snippet => snippet.Topic == edittopic).ToList();
          foreach (var editsnippet in editsnippets)
          {
            editsnippet.Topic = edittopic;
          }

          tv_topic.Items.Clear();
          foreach (var topic in topics)
          {
            tv_topic.Items.Add(topic);
          }

          TopicSelector(edittopic);
        }
        else
        {
          lbl_edittopic_error.Content = "Topic already exists!";
        }

        ResetEditTopic();
        pop_edittopic.IsOpen = false;
      }
    }

    private void DeleteTopic()
    {
      Topic selectedtopic = tv_topic.SelectedItem as Topic;

      List<Snippet> filteredsnippets = snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList();

      foreach (var filteredsnippet in filteredsnippets)
      {
        snippets.Remove(filteredsnippet);
      }

      topics.Remove(selectedtopic);

      tv_topic.Items.Remove(selectedtopic);
      tv_topic.Items.Refresh();

      if (topics.Count == 0)
      {
        btn_deletetopic.Visibility = System.Windows.Visibility.Collapsed;
        btn_edittopic.Visibility = System.Windows.Visibility.Collapsed;
        btn_addsnippet.Visibility = System.Windows.Visibility.Collapsed;
      }

      TopicSelector(topics.Last());
    }

    private void EditSnippet()
    {
      if (tb_editsnippet_name.Text != "" && tb_editsnippet_description.Text != "")
      {
        Snippet editsnippet = lv_snippets.SelectedItem as Snippet;
        Snippet newsnippet = new Snippet()
        {
          Name = tb_editsnippet_name.Text,
          Description = tb_editsnippet_description.Text,
          Date = editsnippet.Date,
          Code = editsnippet.Code,
          Topic = selectedtopic
        };

        snippets.Remove(editsnippet);
        snippets.Add(newsnippet);
        lv_snippets.ItemsSource = snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList();
        lv_snippets.Items.Refresh();
      }
      else if (tb_editsnippet_name.Text == "")
      {
        tb_editsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }
      else if (tb_editsnippet_description.Text == "")
      {
        tb_editsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(254, 0, 0));
      }

      ResetEditSnippet();
      pop_editsnippet.IsOpen = false;
    }

    private void DeleteSnippet()
    {
      Snippet selectedsnippet = lv_snippets.SelectedItem as Snippet;

      snippets.Remove(selectedsnippet);

      lv_snippets.ItemsSource = snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList();
      lv_snippets.Items.Refresh();
      avalonedit.Text = "";

      if (snippets.Count == 0)
      {
        btn_deletesnippet.Visibility = System.Windows.Visibility.Collapsed;
        btn_editsnippet.Visibility = System.Windows.Visibility.Collapsed;
      }

      lv_snippets.SelectedIndex = snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList().Count - 1;
    }







    private void btn_addtopic_Click(object sender, RoutedEventArgs e)
    {
      pop_newtopic.IsOpen = true;
      tb_newtopic.Focus();
    }

    private void btn_addsnippet_Click(object sender, RoutedEventArgs e)
    {
      pop_newsnippet.IsOpen = true;
      tb_newsnippet_name.Focus();
    }

    private void btn_edittopic_Click(object sender, RoutedEventArgs e)
    {
      tb_edittopic.Text = selectedtopic.Name;
      pop_edittopic.IsOpen = true;
      tb_edittopic.Focus();
    }

    private void btn_addtopic_ok_Click(object sender, RoutedEventArgs e)
    {
      AddNewTopic();
    }

    private void btn_addtopic_cancel_Click(object sender, RoutedEventArgs e)
    {
      tb_newtopic.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      pop_newtopic.IsOpen = false;
    }

    private void btn_edittopic_ok_Click(object sender, RoutedEventArgs e)
    {
      EditTopic();
    }

    private void btn_edittopic_cancel_Click(object sender, RoutedEventArgs e)
    {
      ResetEditTopic();
      pop_edittopic.IsOpen = false;
    }

    private void btn_deletetopic_Click(object sender, RoutedEventArgs e)
    {
      lbl_alert_header.Content = "Warning!";
      lbl_alert_content.Text = "Each Snippet which is related to this\nTopic will be deleted as well!\n\nDo you want to proceed?";
      pop_alert.IsOpen = true;
    }

    private void btn_addsnippet_ok_Click(object sender, RoutedEventArgs e)
    {
      AddNewSnippet();
    }

    private void btn_addsnippet_cancel_Click(object sender, RoutedEventArgs e)
    {
      tb_newsnippet_name.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));
      tb_newsnippet_description.BorderBrush = new SolidColorBrush(Color.FromRgb(204, 204, 204));

      tb_newsnippet_name.Text = "";
      tb_newsnippet_description.Text = "";

      pop_newsnippet.IsOpen = false;
    }

    private void btn_savesnippet_Click(object sender, RoutedEventArgs e)
    {
      SaveSnippet();
    }

    private void pop_newtopic_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Escape)
      {
        pop_newtopic.IsOpen = false;
      }
      else if (e.Key == Key.Enter)
      {
        AddNewTopic();
      }
    }

    private void pop_newsnippet_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Escape)
      {
        pop_newsnippet.IsOpen = false;
      }
      else if (e.Key == Key.Enter)
      {
        AddNewSnippet();
      }
    }

    private void pop_edittopic_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Escape)
      {
        pop_edittopic.IsOpen = false;
      }
      else if (e.Key == Key.Enter)
      {
        EditTopic();
      }
    }

    private void pop_editsnippet_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Escape)
      {
        pop_editsnippet.IsOpen = false;
      }
      else if (e.Key == Key.Enter)
      {
        EditSnippet();
      }
    }

    private void btn_alert_ok_Click(object sender, RoutedEventArgs e)
    {
      if (lbl_alert_content.Text.StartsWith("This will delete"))
      {
        DeleteSnippet();
      }
      else
      {
        DeleteTopic();
      }
      pop_alert.IsOpen = false;
    }

    private void btn_alert_cancel_Click(object sender, RoutedEventArgs e)
    {
      pop_alert.IsOpen = false;
    }

    private void btn_editsnippet_Click(object sender, RoutedEventArgs e)
    {
      tb_editsnippet_name.Text = selectedsnippet.Name;
      tb_editsnippet_description.Text = selectedsnippet.Description;
      pop_editsnippet.IsOpen = true;
      tb_editsnippet_name.Focus();
    }

    private void btn_deletesnippet_Click(object sender, RoutedEventArgs e)
    {
      lbl_alert_header.Content = "Warning!";
      lbl_alert_content.Text = "This will delete this Snippet!\n\nDo you want to proceed?";
      pop_alert.IsOpen = true;
    }

    private void lv_snippets_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Delete)
      {
        DeleteSnippet();
      }
    }

    private void tv_topic_KeyUp(object sender, KeyEventArgs e)
    {
      if (e.Key == Key.Delete)
      {
        DeleteTopic();
      }
    }

    private void tv_topic_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
      if (selectedtopic != tv_topic.SelectedItem as Topic)
      {
        if (selectedtopic != null)
        {
          selectedtopic = tv_topic.SelectedItem as Topic;
        }
        else
        {
          selectedtopic = topics[topics.Count - 1];
        }

        if (snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList().Count == 0)
        {
          avalonedit.IsEnabled = false;
        }

        List<Snippet> topicsnippets = snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList();
        btn_deletetopic.Visibility = System.Windows.Visibility.Visible;
        btn_addsnippet.Visibility = System.Windows.Visibility.Visible;
        btn_edittopic.Visibility = System.Windows.Visibility.Visible;

        avalonedit.Text = "";
        avalonedit.IsEnabled = false;

        try
        {
          Snippet s = (snippets.Where(snippet => snippet.Topic.Name == selectedtopic.Name).ToList())[0];

          lv_snippets.SelectedItem = s;
          lv_snippets.ScrollIntoView(lv_snippets.SelectedItem);
          lv_snippets.ItemsSource = topicsnippets;
        }
        catch
        {
          lv_snippets.ItemsSource = null;
          selectedsnippet = null;
        }

        if (topics.Count == 0)
        {
          btn_editsnippet.Visibility = System.Windows.Visibility.Collapsed;
          btn_deletesnippet.Visibility = System.Windows.Visibility.Collapsed;
        }
      }
    }

    private void lv_snippets_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      try
      {
        selectedsnippet = lv_snippets.SelectedItem as Snippet;
        avalonedit.Text = selectedsnippet.Code;
        avalonedit.IsEnabled = true;
      }
      catch
      {
      }
      btn_editsnippet.Visibility = System.Windows.Visibility.Visible;
      btn_deletesnippet.Visibility = System.Windows.Visibility.Visible;
    }

    private void avalonedit_PreviewKeyDown(object sender, KeyEventArgs e)
    {
      if (Keyboard.IsKeyDown(Key.LeftCtrl) && Keyboard.IsKeyDown(Key.S))
      {
        SaveSnippet();
      }
      else
      {
        btn_savesnippet.Visibility = System.Windows.Visibility.Visible;
        autosavetimer.Start();
      }
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
      TopicSelector(topics[0]);
    }

    private void btn_editsnippet_ok_Click(object sender, RoutedEventArgs e)
    {
      EditSnippet();
    }

    private void btn_editsnippet_cancel_Click(object sender, RoutedEventArgs e)
    {
      pop_editsnippet.IsOpen = false;
    }

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
      XMLSerializer.SerializeToXML(snippets);
      XMLSerializer.SerializeToXML(topics);
    }
  }
}
